package org.rency.ues.domainservice.manage.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.rency.common.utils.security.Base64Utils;
import org.rency.common.utils.security.X509CertUtils;
import org.rency.ues.dal.entity.CertificationDO;
import org.rency.ues.dal.repository.CertificationRepository;
import org.rency.ues.domainservice.manage.CertificationManager;
import org.rency.ues.domainservice.support.Certification;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

public class CertificationManagerImpl implements CertificationManager, InitializingBean {

	private static final Logger logger = LoggerFactory.getLogger(CertificationManagerImpl.class);
	private ConcurrentHashMap<String, Certification> certifications = new ConcurrentHashMap<String, Certification>();
	private ConcurrentHashMap<String, Long> versions = new ConcurrentHashMap<String, Long>();
	@Resource(name="certificationRepository")
	private CertificationRepository certificationRepository;

	private void loadCertifications(){		
		List<Certification> certs = new ArrayList<Certification>();
		List<CertificationDO> certList = certificationRepository.loadAll();
		if(CollectionUtils.isEmpty(certList)){
			throw new RuntimeException("load all certification error, because no item!");
		}
		for(CertificationDO entity : certList){
			if (!this.certifications.containsKey(entity.getCertVersion())) {
				Certification cert =this.build(entity);
				if (cert.isValidate()) {
					certs.add(cert);
					this.certifications.put(this.buildKey(cert.getSerialNo(), cert.getVersion()), cert);
					this.versions.put(cert.getSerialNo(), cert.getVersion());
				}
			}
		}
        logger.info("init certification finished, and total [{}] size.",certs.size());
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		this.loadCertifications();
	}

	public void setCertificationRepository(CertificationRepository certificationRepository) {
		this.certificationRepository = certificationRepository;
	}

	@Override
	public Certification getCertification(String serialNo, long version) {
		Assert.notNull(serialNo, "证书序列号不能为空");
		if(version == 0){
			version = this.versions.get(serialNo);
		}
		String key = this.buildKey(serialNo, version);
		if(!this.certifications.containsKey(key)){
			this.refresh();
		}
		return this.certifications.get(key);
	}

	@Override
	public void refresh() {
		logger.info("refresh certification container.");
		this.certifications.clear();
		this.loadCertifications();
	}
	
	private String buildKey(String serialNo,long version){
		return serialNo+"-"+version;
	}

	private Certification build(CertificationDO entity){
		Certification certification = new Certification();
		certification.setPath(entity.getCertPath());
		certification.setPassword(entity.getCertPasswd());
		certification.setVersion(entity.getCertVersion());
		certification.setSerialNo(entity.getSerialNo());
    	try {
    		certification.setCertificate(X509CertUtils.getX509CertFromPfxFile(entity.getCertPath(), entity.getCertPasswd()));
    		certification.setPrivateKey(X509CertUtils.getPrivateKeyByPfxFile(entity.getCertPath(), entity.getCertPasswd()));
    		certification.setCertBase(Base64Utils.encodeBase64String(certification.getCertificate().getEncoded()));
    		certification.setValidate(true);
		} catch (Exception e) {
			throw new RuntimeException("Load certification exceptions");
		}
    	certification.setUpdateTime(entity.getUpdateTime());
    	certification.setCreateTime(entity.getCreateTime());
		return certification;
	}
}